home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Sprite 1984 - 1993
/
Sprite 1984 - 1993.iso
/
src
/
kernel
/
rpc
/
rpcInit.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-12-18
|
16KB
|
508 lines
/*
* rpcInit.c --
*
* Initialize the data structures needed by the RPC system.
*
* Copyright (C) 1985 Regents of the University of California
* All rights reserved.
*/
#ifndef lint
static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/rpc/rpcInit.c,v 9.14 92/04/14 17:04:27 jhh Exp $ SPRITE (Berkeley)";
#endif /* not lint */
#include <sprite.h>
#include <stdio.h>
#include <rpc.h>
#include <rpcInt.h>
#include <rpcClient.h>
#include <rpcServer.h>
#include <rpcTrace.h>
#include <vm.h>
#include <timer.h>
#include <net.h>
/*
* These are the rpc version numbers, both in native format and in
* byte-swapped format.
*/
int rpc_NativeVersion = RPC_NATIVE_VERSION;
int rpc_SwappedVersion = RPC_SWAPPED_VERSION;
/*
* Constant parameters for the protocol. The RpcConst structure keeps
* the complete set of constants. Two sets of constants are defined,
* one that is appropriate for a local ethernet, one that has longer
* timeouts and is better for talking across gateways.
*/
RpcConst rpcEtherConst;
RpcConst rpcInetConst;
void RpcBufferInit();
/*
*----------------------------------------------------------------------
*
* Rpc_Init --
*
* Allocate and set up the tables used by the RPC system. This
* should be called after virtual memory allocation can be done and
* before any RPCs are attempted. This allocates the Client Channel
* data structures and some stuff for the Rpc Servers' state. The
* number of client channels is fixed by rpcNumChannels, but the
* number of RPC server processes can grow via the Rpc_Deamon process.
*
* Results:
* None.
*
* Side effects:
* Allocate space for tables, and set the initial state for the
* client channels and the servers.
*
*----------------------------------------------------------------------
*/
void
Rpc_Init()
{
int i;
register int frag;
extern void RpcInitServerTraces();
/*
* Initialize sets of time parameters. These structures are used in
* the RpcDoCall code. This is much too hard coded, and someone
* should figure out how to dynamically determine these parameters.
*
* Ethernet - retry after 0.1 seconds, .5 seconds if fragmenting.
* Double this until the retry interval is 1 second.
* Retry at most 8 times, for a total timeout period of
* .1 + .2 + .4 + .8 + 1.0 + 1.0 + 1.0 + 1.0 = 5.5
* .5 + 1.0 + 1.0 + 1.0 + 1.0 + 1.0 + 1.0 + 1.0 = 7.5 (frag)
* If we are recieving acks, then back off and probe every 5 seconds.
* If we get acked 10 times then give a warning.
*/
rpcEtherConst.retryMsec = 100;
rpcEtherConst.retryWait = 100 * timer_IntOneMillisecond;
rpcEtherConst.fragRetryMsec = 500;
rpcEtherConst.fragRetryWait = 500 * timer_IntOneMillisecond;
rpcEtherConst.maxAckMsec = 5000;
rpcEtherConst.maxAckWait = 5000 * timer_IntOneMillisecond;
rpcEtherConst.maxTimeoutMsec = 1000;
rpcEtherConst.maxTimeoutWait = 1000 * timer_IntOneMillisecond;
rpcEtherConst.maxTries = 8;
rpcEtherConst.maxAcks = 10;
/*
* Internet (IP) - retry after 0.5 seconds, 1.0 if fragmenting.
* Double this until the retry interval is 4 seconds.
* Retry at most 8 times, for a total timeout period of
* .5 + 1.0 + 2.0 + 4.0 + 4.0 + 4.0 + 4.0 + 4.0 = 23.5
* 1.0 + 2.0 + 4.0 + 4.0 + 4.0 + 4.0 + 4.0 + 4.0 = 27.0 (frag)
* If we are recieving acks, then back off and probe every 5 seconds.
* If we get acked 10 times then give a warning.
*/
rpcInetConst.retryMsec = 500;
rpcInetConst.retryWait = 500 * timer_IntOneMillisecond;
rpcInetConst.fragRetryMsec = 1000;
rpcInetConst.fragRetryWait = 1000 * timer_IntOneMillisecond;
rpcInetConst.maxAckMsec = 5000;
rpcInetConst.maxAckWait = 5000 * timer_IntOneMillisecond;
rpcInetConst.maxTimeoutMsec = 4000;
rpcInetConst.maxTimeoutWait = 4000 * timer_IntOneMillisecond;
rpcInetConst.maxTries = 8;
rpcInetConst.maxAcks = 10;
/*
* TRACE and HISTOGRAM initialization.
*/
Trace_Init(rpcTraceHdrPtr, RPC_TRACE_LEN, sizeof(RpcHdr), 0);
rpcServiceTime[0] = (Rpc_Histogram *)NIL;
rpcCallTime[0] = (Rpc_Histogram *)NIL;
for (i=1 ; i<=RPC_LAST_COMMAND ; i++) {
rpcServiceTime[i] = Rpc_HistInit(RPC_NUM_HIST_BUCKETS, 1024);
rpcCallTime[i] = Rpc_HistInit(RPC_NUM_HIST_BUCKETS, 1024);
}
/*
* Set our preferred inter-fragment delay based on machine type.
* This is a microsecond value. Our output rate starts the same
* as the input rate, although MyDelay could increase if a machine
* senses that it is overloaded.
*/
RpcGetMachineDelay(&rpcMyDelay, &rpcOutputRate);
/*
* The client channel table is kept as a pointer to an array of pointers
* to client channels. First allocate the table of pointers and then
* allocate storage for each channel.
*/
rpcChannelPtrPtr = (RpcClientChannel **)
Vm_RawAlloc(rpcNumChannels * sizeof(RpcClientChannel *));
/*
* Query the net module of the maximum size protocol header buffer
* needed.
*/
for (i=0 ; i<rpcNumChannels ; i++) {
register RpcClientChannel *chanPtr;
chanPtr = (RpcClientChannel *)Vm_RawAlloc(sizeof(RpcClientChannel));
rpcChannelPtrPtr[i] = chanPtr;
chanPtr->state = CHAN_FREE;
chanPtr->index = i;
chanPtr->serverID = -1;
Sync_SemInitDynamic(&chanPtr->mutex,"Rpc:RpcClientChannel.mutex");
Sync_SemRegister(&chanPtr->mutex);
chanPtr->waitCondition.waiting = FALSE;
/*
* Set up header storage and the scatter/gather sets used to
* refer to a whole message. This is done for each type
* of packet (request, reply ack), plus an array of these
* things used for fragmenting our request.
*/
RpcBufferInit((RpcHdr *) &chanPtr->requestRpcHdr, &chanPtr->request,
chanPtr->index, -1);
RpcBufferInit(&chanPtr->replyRpcHdr, &chanPtr->reply,
chanPtr->index, -1);
RpcBufferInit(&chanPtr->ackHdr, &chanPtr->ack,
chanPtr->index, -1);
for (frag=0 ; frag < RPC_MAX_NUM_FRAGS ; frag++) {
RpcBufferInit(&chanPtr->fragRpcHdr[frag], &chanPtr->fragment[frag],
chanPtr->index, -1);
}
}
/*
* Initialize server nack info.
*/
Sync_SemInitDynamic(&rpcNack.mutex,"Rpc:RpcNackData.mutex");
Sync_SemRegister(&rpcNack.mutex);
/*
* Set nack buffers to NIL until allocated when rpc system turned on.
*/
rpcNack.numFree = 0;
rpcNack.rpcHdrArray = (RpcHdr *) NIL;
rpcNack.hdrState = (int *) NIL;
rpcNack.bufferSet = (RpcBufferSet *) NIL;
/*
* Initialize client's table on whether servers are sending negative
* acknowledgements or not (if channel ramping-down is used).
*/
RpcInitServerChannelState();
/*
* Initialize neg-ack back-off constants on clients.
*/
rpcNackRetryWait = 2 * timer_IntOneSecond;
rpcMaxNackWait = 15 * timer_IntOneSecond;
/*
* Initialize the servers' state table. Most slots are left
* uninitialized. They get filled in by Rpc_Deamon when it creates
* new server processes. After creation, a server process
* claims a table entry with RpcServerInstall.
*/
rpcServerPtrPtr = (RpcServerState **)
Vm_RawAlloc(rpcAbsoluteMaxServers * sizeof(RpcServerState *));
for (i=0 ; i<rpcMaxServers ; i++) {
rpcServerPtrPtr[i] = (RpcServerState *)NIL;
}
/*
* Ask the net module to set up our Sprite ID. It uses either
* existing (compiled in) addresses or Reverse ARP. If we can't
* figure out our ID we use zero and rely on the RPC server to
* propogate our Sprite ID back in the first RPC reply message.
* We try all the interfaces until we get one that works.
*/
for (i = 0; ; i++) {
Net_Interface *interPtr;
interPtr = Net_NextInterface(TRUE, &i);
if (interPtr == (Net_Interface *) NIL) {
break;
}
rpc_SpriteID = Net_AddrToID(&interPtr->netAddress[NET_PROTO_RAW]);
if (rpc_SpriteID > 0) {
break;
}
}
if (rpc_SpriteID < 0) {
rpc_SpriteID = 0;
}
RpcInitServerTraces();
return;
}
/*
*----------------------------------------------------------------------
*
* RpcBufferInit --
*
* Initialize a packet buffer for one of the various packets sent
* via an RPC channel. They all share the same packet format and
* buffering system, and this call is used to initialize it.
*
* Results:
* None.
*
* Side effects:
* Allocate memory with Vm_RawAlloc. Give initial values to
* the fields of the RPC header that never change. These are:
* version # byte ordering version.
* channel # channel port number.
* delay # interfragment delay.
* paramSize 0 # size of the parameter area of the message.
* dataSize 0 # size of the data area of the message.
* numFrags 0 # >0 if fragmented
* fragMask 0 # fragmentID
*
*----------------------------------------------------------------------
*/
void
RpcBufferInit(rpcHdrPtr, bufferSetPtr, channel, serverHint)
RpcHdr *rpcHdrPtr; /* Storage for packet header */
RpcBufferSet *bufferSetPtr; /* Scatter/gather vector for whole message */
int channel; /* chanPtr->index */
int serverHint; /* srvPtr->index */
{
int maxHdrSize = NET_MAX_HEADER_SIZE;
bufferSetPtr->protoHdrBuffer.length = maxHdrSize;
bufferSetPtr->protoHdrBuffer.bufAddr = Vm_RawAlloc(maxHdrSize);
bufferSetPtr->protoHdrBuffer.mutexPtr = (Sync_Semaphore *)NIL;
bufferSetPtr->rpcHdrBuffer.length = sizeof(RpcHdr);
bufferSetPtr->rpcHdrBuffer.bufAddr = (Address)rpcHdrPtr;
bufferSetPtr->rpcHdrBuffer.mutexPtr = (Sync_Semaphore *)NIL;
bufferSetPtr->paramBuffer.length = 0;
bufferSetPtr->paramBuffer.bufAddr = (Address)NIL;
bufferSetPtr->paramBuffer.mutexPtr = (Sync_Semaphore *)NIL;
bufferSetPtr->dataBuffer.length = 0;
bufferSetPtr->dataBuffer.bufAddr = (Address)NIL;
bufferSetPtr->dataBuffer.mutexPtr = (Sync_Semaphore *)NIL;
/*
* Set up RPC header fields that don't change.
*/
rpcHdrPtr->version = rpc_NativeVersion;
rpcHdrPtr->delay = rpcMyDelay;
rpcHdrPtr->clientID = rpc_SpriteID;
rpcHdrPtr->channel = channel;
rpcHdrPtr->serverID = rpc_SpriteID;
rpcHdrPtr->serverHint = serverHint;
/*
* And some that might not have to change.
*/
rpcHdrPtr->numFrags = 0;
rpcHdrPtr->fragMask = 0;
rpcHdrPtr->paramSize = 0;
rpcHdrPtr->dataSize = 0;
}
/*
*----------------------------------------------------------------------
*
* RpcInitServerState --
*
* Initialize a server state table entry. This is called before
* a server process is created to set up its state. The state is
* used as the primary communication mechanism between the server
* process and the rest of the world.
*
* Results:
* A pointer to an initialized server state table entry. This
* value needs to be saved in a table somewhere by the caller.
*
* Side effects:
* Allocate memory with Vm_RawAlloc. Give initial values to
* all the elements of the table entry. The "state" field of
* the table is set to SRV_NOTREADY and a server process has
* to claim the table entry with RpcServerInstall.
*
*----------------------------------------------------------------------
*/
RpcServerState *
RpcInitServerState(index)
int index; /* Caller's index of returned info. This is saved
* in the table and used as a hint to clients */
{
register RpcServerState *srvPtr; /* Server state that is initialized */
register int frag; /* Index into array of headers used
* for fragmenting */
static Sync_Semaphore mutexInit =
Sync_SemInitStatic("RpcServerState->mutex");
Sync_SemRegister(&mutexInit);
srvPtr = (RpcServerState *)Vm_RawAlloc(sizeof(RpcServerState));
srvPtr->state = SRV_NOTREADY;
srvPtr->ID = 0;
srvPtr->freeReplyProc = (int (*)())NIL;
srvPtr->freeReplyData = (ClientData)NIL;
srvPtr->index = index;
srvPtr->clientID = -1;
srvPtr->channel = -1;
srvPtr->mutex = mutexInit;
srvPtr->waitCondition.waiting = FALSE;
/*
* Set up the buffer address for the RPC header of replies
* and acks to point to the headers kept here in the server's state.
*/
RpcBufferInit(&srvPtr->replyRpcHdr, &srvPtr->reply, -1, srvPtr->index);
RpcBufferInit(&srvPtr->ackRpcHdr, &srvPtr->ack, -1, srvPtr->index);
for (frag=0 ; frag < RPC_MAX_NUM_FRAGS ; frag++) {
RpcBufferInit(&srvPtr->fragRpcHdr[frag], &srvPtr->fragment[frag],
-1, srvPtr->index);
}
/*
* Set up the scatter vector for input requests to the server.
* Allocate buffer space for the largest possible request.
*/
RpcBufferInit(&srvPtr->requestRpcHdr, &srvPtr->request, -1, srvPtr->index);
srvPtr->request.paramBuffer.bufAddr = Vm_RawAlloc(RPC_MAX_PARAMSIZE);
srvPtr->request.paramBuffer.length = RPC_MAX_PARAMSIZE;
srvPtr->request.dataBuffer.bufAddr = Vm_RawAlloc(RPC_MAX_DATASIZE);
srvPtr->request.dataBuffer.length = RPC_MAX_DATASIZE;
/*
* Initialize temporaries.
*/
srvPtr->actualParamSize = 0;
srvPtr->actualDataSize = 0;
return(srvPtr);
}
/*
*----------------------------------------------------------------------
*
* Rpc_Start --
*
* Conduct the preliminary RPC's neccesary to start up the client
* side of the RPC system. A Get Time RPC is done to initialize the
* boot time stamp.
*
* Results:
* None.
*
* Side effects:
* Do a Get Time RPC to initialize rpcBootID;
*
*----------------------------------------------------------------------
*/
void
Rpc_Start()
{
Time bootTime; /* Time returned from the default server */
int tzMinutes; /* Minutes west of Greenwich */
int tzDST; /* Daylight savings flag */
ReturnStatus status; /* Status code from the RPC */
char dateString[40];/* To hold a printable version of the time */
int seconds;
int spriteID;
Net_Route *routePtr;
Sync_Semaphore tmpMutex;
int i;
/*
* Do a Sprite reverse Arp to discover our Sprite ID. If it's still
* zero after this that inhibits the RPC system. In that case we'd
* better be a diskfull machine so we find out our SpriteID by
* the user program that installs routes. See Net_InstallRoute.
*
* We do a reverse arp on all the broadcast routes until one
* works.
*/
spriteID = -1;
i = 0;
Sync_SemInitDynamic(&tmpMutex, "Rpc_Start:tmpMutex");
while (1) {
routePtr = Net_IDToRoute(NET_BROADCAST_HOSTID, i, FALSE,
(Sync_Semaphore *) NIL, 0);
if (routePtr == (Net_Route *) NIL) {
break;
}
MASTER_LOCK(&tmpMutex);
spriteID = Net_RevArp(routePtr, NET_PROTO_RAW,
(Net_Address *) NIL, &tmpMutex);
MASTER_UNLOCK(&tmpMutex);
Net_ReleaseRoute(routePtr);
if (spriteID > 0) {
rpc_SpriteID = spriteID;
printf("Reverse Arp, setting Sprite ID to %d\n", spriteID);
break;
}
i++;
}
Rpc_StampTest();
status = Rpc_GetTime(RPC_BROADCAST_SERVER_ID, &bootTime, &tzMinutes,
&tzDST);
if (status != SUCCESS) {
Timer_Ticks ticks;
printf("Rpc_Start: error (%x) from Get Time RPC\n", status);
Timer_GetCurrentTicks(&ticks);
Timer_TicksToTime(ticks, &bootTime);
} else {
Timer_SetTimeOfDay(bootTime, tzMinutes, tzDST);
}
rpcBootID = bootTime.seconds;
/*
* Convert from Greenwich Standard minutes to local minutes
* and print the time on the console.
*/
seconds = bootTime.seconds + tzMinutes * 60;
Time_ToAscii(seconds, FALSE, dateString);
printf("%s\n", dateString);
}
/*
*----------------------------------------------------------------------
*
* Rpc_MaxSizes --
*
* This function returns the maximum amount of data that can be sent
* in one RPC. A remote procedure has its inputs and outputs packed
* into two buffers called the "data area" and the "parameter area".
* Two values are returned, the maximums for the parameter and data
* areas.
*
* Results:
* The first parameter gets the maximum data size, the
* second gets the maximum parameter size.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
void
Rpc_MaxSizes(maxDataSizePtr, maxParamSizePtr)
int *maxDataSizePtr;
int *maxParamSizePtr;
{
if (maxDataSizePtr != (int *)NIL){
*maxDataSizePtr = RPC_MAX_DATASIZE;
}
if (maxParamSizePtr != (int *)NIL){
*maxParamSizePtr = RPC_MAX_PARAMSIZE;
}
}